* API: (bug 17774) API pretends action=query doesn't exist for users without read...
authorRoan Kattouw <catrope@users.mediawiki.org>
Fri, 6 Mar 2009 13:49:44 +0000 (13:49 +0000)
committerRoan Kattouw <catrope@users.mediawiki.org>
Fri, 6 Mar 2009 13:49:44 +0000 (13:49 +0000)
* Instead of hiding read-restricted modules, throw an error when a user without read rights tries to use them
* Do the same for write modules when $wgEnableWriteAPI is false
* Indicate whether a module needs read or write rights in action=help and action=paraminfo
* BREAKING CHANGE: action=purge now requires write rights and, for anonymous users, a POST request

21 files changed:
RELEASE-NOTES
includes/api/ApiBase.php
includes/api/ApiBlock.php
includes/api/ApiDelete.php
includes/api/ApiDisabled.php
includes/api/ApiEditPage.php
includes/api/ApiEmailUser.php
includes/api/ApiHelp.php
includes/api/ApiImport.php
includes/api/ApiLogin.php
includes/api/ApiLogout.php
includes/api/ApiMain.php
includes/api/ApiMove.php
includes/api/ApiParamInfo.php
includes/api/ApiPatrol.php
includes/api/ApiProtect.php
includes/api/ApiPurge.php
includes/api/ApiRollback.php
includes/api/ApiUnblock.php
includes/api/ApiUndelete.php
includes/api/ApiWatch.php

index 501d468..970fbb5 100644 (file)
@@ -283,6 +283,12 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
   conversion rules
 * (bug 17795) Don't report views count on meta=siteinfo if $wgDisableCounters 
   is set
+* (bug 17774) Don't hide read-restricted modules like action=query from users
+  without read rights, but throw an error when they try to use them.
+* Don't hide write modules when $wgEnableWriteAPI is false, but throw an error
+  when someone tries to use them
+* BREAKING CHANGE: action=purge requires write rights and, for anonymous users,
+  a POST request
 
 === Languages updated in 1.15 ===
 
index ad2b4e4..4ab5f25 100644 (file)
@@ -218,8 +218,15 @@ abstract class ApiBase {
                                );
                        $msg = $lnPrfx . implode($lnPrfx, $msg) . "\n";
 
+                       if ($this->isReadMode())
+                               $msg .= "\nThis module requires read rights.";
+                       if ($this->isWriteMode())
+                               $msg .= "\nThis module requires write rights.";
                        if ($this->mustBePosted())
-                               $msg .= "\nThis module only accepts POST requests.\n";
+                               $msg .= "\nThis module only accepts POST requests.";
+                       if ($this->isReadMode() || $this->isWriteMode() ||
+                                       $this->mustBePosted())
+                               $msg .= "\n";
 
                        // Parameters
                        $paramsMsg = $this->makeHelpMsgParameters();
@@ -758,6 +765,9 @@ abstract class ApiBase {
                'movenotallowedfile' => array('code' => 'cantmovefile', 'info' => "You don't have permission to move files"),
 
                // API-specific messages
+               'readrequired' => array('code' => 'readapidenied', 'info' => "You need read permission to use this module"),
+               'writedisabled' => array('code' => 'noapiwrite', 'info' => "Editing of this wiki through the API is disabled. Make sure the \$wgEnableWriteAPI=true; statement is included in the wiki's LocalSettings.php file"),
+               'writerequired' => array('code' => 'writeapidenied', 'info' => "You're not allowed to edit this wiki through the API"),
                'missingparam' => array('code' => 'no$1', 'info' => "The \$1 parameter must be set"),
                'invalidtitle' => array('code' => 'invalidtitle', 'info' => "Bad title ``\$1''"),
                'nosuchpageid' => array('code' => 'nosuchpageid', 'info' => "There is no page with ID \$1"),
@@ -855,10 +865,17 @@ abstract class ApiBase {
        }
 
        /**
-        * Indicates if this module requires edit mode
+        * Indicates whether this module requires read rights
         * @return bool
         */
-       public function isEditMode() {
+       public function isReadMode() {
+               return true;
+       }
+       /**
+        * Indicates whether this module requires write mode
+        * @return bool
+        */
+       public function isWriteMode() {
                return false;
        }
 
index 7d8b087..fc77f2a 100644 (file)
@@ -50,7 +50,6 @@ class ApiBlock extends ApiBase {
         */
        public function execute() {
                global $wgUser, $wgBlockAllowsUTEdit;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                if($params['gettoken'])
@@ -115,6 +114,10 @@ class ApiBlock extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'user' => null,
index a892b1c..a923021 100644 (file)
@@ -49,7 +49,6 @@ class ApiDelete extends ApiBase {
         */
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                $this->requireOnlyOneParameter($params, 'title', 'pageid');
@@ -178,6 +177,10 @@ class ApiDelete extends ApiBase {
        
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'title' => null,
index 3136384..c4cd621 100644 (file)
@@ -48,6 +48,10 @@ class ApiDisabled extends ApiBase {
                $this->dieUsage("The ``{$this->getModuleName()}'' module has been disabled.", 'moduledisabled');
        }
 
+       public function isReadMode() {
+               return false;
+       }
+
        public function getAllowedParams() {
                return array ();
        }
index 8fc3f15..a66006b 100644 (file)
@@ -43,8 +43,6 @@ class ApiEditPage extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
-
                $params = $this->extractRequestParams();
                if(is_null($params['title']))
                        $this->dieUsageMsg(array('missingparam', 'title'));
@@ -275,6 +273,10 @@ class ApiEditPage extends ApiBase {
                return true;
        }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        protected function getDescription() {
                return 'Create and edit pages.';
        }
index 5548b18..e1fe85e 100644 (file)
@@ -39,14 +39,11 @@ class ApiEmailUser extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               
                // Check whether email is enabled
                if ( !EmailUserForm::userEmailEnabled() )
                        $this->dieUsageMsg( array( 'usermaildisabled' ) );
-               
-               $this->getMain()->requestWriteMode();
+
                $params = $this->extractRequestParams();
-               
                // Check required parameters
                if ( !isset( $params['target'] ) )
                        $this->dieUsageMsg( array( 'missingparam', 'target' ) );
@@ -79,6 +76,10 @@ class ApiEmailUser extends ApiBase {
        
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'target' => null,
index 50e33fe..982bf4d 100644 (file)
@@ -50,6 +50,10 @@ class ApiHelp extends ApiBase {
                return false;
        }
 
+       public function isReadMode() {
+               return false;
+       }
+
        public function getDescription() {
                return array (
                        'Display this help screen.'
index ef2f51e..cba0c56 100644 (file)
@@ -41,7 +41,6 @@ class ApiImport extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                if(!$wgUser->isAllowed('import'))
                        $this->dieUsageMsg(array('cantimport'));
                $params = $this->extractRequestParams();
@@ -101,6 +100,10 @@ class ApiImport extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                global $wgImportSources;
                return array (
index b197c20..66ff8df 100644 (file)
@@ -125,6 +125,10 @@ class ApiLogin extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isReadMode() {
+               return false;
+       }
+
        public function getAllowedParams() {
                return array (
                        'name' => null,
index 000409e..1fb9c31 100644 (file)
@@ -50,6 +50,10 @@ class ApiLogout extends ApiBase {
                wfRunHooks( 'UserLogoutComplete', array(&$wgUser, &$injected_html, $oldName) );
        }
 
+       public function isReadMode() {
+               return false;
+       }
+
        public function getAllowedParams() {
                return array ();
        }
index a2b9814..3fa0d72 100644 (file)
@@ -65,10 +65,9 @@ class ApiMain extends ApiBase {
                'feedwatchlist' => 'ApiFeedWatchlist',
                'help' => 'ApiHelp',
                'paraminfo' => 'ApiParamInfo',
-               'purge' => 'ApiPurge',
-       );
 
-       private static $WriteModules = array (
+               // Write modules
+               'purge' => 'ApiPurge',
                'rollback' => 'ApiRollback',
                'delete' => 'ApiDelete',
                'undelete' => 'ApiUndelete',
@@ -150,20 +149,10 @@ class ApiMain extends ApiBase {
                                wfDebug( "API: stripping user credentials for JSON callback\n" );
                                $wgUser = new User();
                        }
-
-                       if (!$wgUser->isAllowed('read')) {
-                               self::$Modules = array(
-                                       'login'  => self::$Modules['login'],
-                                       'logout' => self::$Modules['logout'],
-                                       'help'   => self::$Modules['help'],
-                                       );
-                       }
                }
 
-               global $wgAPIModules, $wgEnableWriteAPI; // extension modules
+               global $wgAPIModules; // extension modules
                $this->mModules = $wgAPIModules + self :: $Modules;
-               if($wgEnableWriteAPI)
-                       $this->mModules += self::$WriteModules;
 
                $this->mModuleNames = array_keys($this->mModules);
                $this->mFormats = self :: $Formats;
@@ -200,24 +189,6 @@ class ApiMain extends ApiBase {
                return $this->mResult;
        }
 
-       /**
-        * This method will simply cause an error if the write mode was disabled
-        * or if the current user doesn't have the right to use it
-        */
-       public function requestWriteMode() {
-               global $wgUser;
-               if (!$this->mEnableWrite)
-                       $this->dieUsage('Editing of this wiki through the API' .
-                       ' is disabled. Make sure the $wgEnableWriteAPI=true; ' .
-                       'statement is included in the wiki\'s ' .
-                       'LocalSettings.php file', 'noapiwrite');
-               if (!$wgUser->isAllowed('writeapi'))
-                       $this->dieUsage('You\'re not allowed to edit this ' .
-                       'wiki through the API', 'writeapidenied');
-               if (wfReadOnly())
-                       $this->dieUsageMsg(array('readonlytext'));
-       }
-
        /**
         * Set how long the response should be cached.
         */
@@ -410,6 +381,18 @@ class ApiMain extends ApiBase {
                        }
                }
 
+               global $wgUser;
+               if ($module->isReadMode() && !$wgUser->isAllowed('read'))
+                       $this->dieUsageMsg(array('readrequired'));
+               if ($module->isWriteMode()) {
+                       if (!$this->mEnableWrite)
+                               $this->dieUsageMsg(array('writedisabled'));
+                       if (!$wgUser->isAllowed('writeapi'))
+                               $this->dieUsageMsg(array('writerequired'));
+                       if (wfReadOnly())
+                               $this->dieUsageMsg(array('readonlytext'));
+               }
+
                if (!$this->mInternalMode) {
                        // Ignore mustBePosted() for internal calls
                        if($module->mustBePosted() && !$this->mRequest->wasPosted())
@@ -458,6 +441,10 @@ class ApiMain extends ApiBase {
                $printer->closePrinter();
                $printer->profileOut();
        }
+       
+       public function isReadMode() {
+               return false;
+       }
 
        /**
         * See ApiBase for description.
index c3a5e7d..975a8ba 100644 (file)
@@ -39,7 +39,6 @@ class ApiMove extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
                if(is_null($params['reason']))
                        $params['reason'] = '';
@@ -155,6 +154,10 @@ class ApiMove extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'from' => null,
index 7bc73b9..e8f7b2a 100644 (file)
@@ -93,6 +93,12 @@ class ApiParamInfo extends ApiBase {
                $retval['classname'] = get_class($obj);
                $retval['description'] = (is_array($obj->getDescription()) ? implode("\n", $obj->getDescription()) : $obj->getDescription());
                $retval['prefix'] = $obj->getModulePrefix();
+               if($obj->isReadMode())
+                       $retval['readrights'] = '';
+               if($obj->isWriteMode())
+                       $retval['writerights'] = '';
+               if($obj->mustBePosted())
+                       $retval['mustbeposted'] = '';
                $allowedParams = $obj->getFinalParams();
                if(!is_array($allowedParams))
                        return $retval;
@@ -147,6 +153,10 @@ class ApiParamInfo extends ApiBase {
                return $retval;
        }
 
+       public function isReadMode() {
+               return false;
+       }
+
        public function getAllowedParams() {
                return array (
                        'modules' => array(
index 5949f00..dd57fd5 100644 (file)
@@ -42,7 +42,6 @@ class ApiPatrol extends ApiBase {
         */
        public function execute() {
                global $wgUser, $wgUseRCPatrol, $wgUseNPPatrol;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
                
                if(!isset($params['token']))
@@ -65,6 +64,10 @@ class ApiPatrol extends ApiBase {
                $this->getResult()->addValue(null, $this->getModuleName(), $result);
        }
 
+       public function getWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'token' => null,
index 6bae2fc..66b284e 100644 (file)
@@ -38,7 +38,6 @@ class ApiProtect extends ApiBase {
 
        public function execute() {
                global $wgUser, $wgRestrictionTypes, $wgRestrictionLevels;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                $titleObj = NULL;
@@ -127,6 +126,10 @@ class ApiProtect extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'title' => null,
index a0c0808..e2d0008 100644 (file)
@@ -74,6 +74,15 @@ class ApiPurge extends ApiBase {
                $this->getResult()->addValue(null, $this->getModuleName(), $result);
        }
 
+       public function mustBePosted() {
+               global $wgUser;
+               return $wgUser->isAnon();
+       }
+
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'titles' => array(
index cb0486f..0ff602d 100644 (file)
@@ -37,7 +37,6 @@ class ApiRollback extends ApiBase {
        }
 
        public function execute() {
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                $titleObj = NULL;
@@ -84,6 +83,10 @@ class ApiRollback extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'title' => null,
index b8568bc..b36b3b4 100644 (file)
@@ -44,7 +44,6 @@ class ApiUnblock extends ApiBase {
         */
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                if($params['gettoken'])
@@ -80,6 +79,10 @@ class ApiUnblock extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'id' => null,
index 9bb2efb..9a1e927 100644 (file)
@@ -38,7 +38,6 @@ class ApiUndelete extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                $params = $this->extractRequestParams();
 
                $titleObj = NULL;
@@ -86,6 +85,10 @@ class ApiUndelete extends ApiBase {
 
        public function mustBePosted() { return true; }
 
+       public function isWriteMode() {
+               return true;
+       }
+
        public function getAllowedParams() {
                return array (
                        'title' => null,
index 5683912..94569b6 100644 (file)
@@ -41,7 +41,6 @@ class ApiWatch extends ApiBase {
 
        public function execute() {
                global $wgUser;
-               $this->getMain()->requestWriteMode();
                if(!$wgUser->isLoggedIn())
                        $this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin');
                $params = $this->extractRequestParams();
@@ -65,6 +64,10 @@ class ApiWatch extends ApiBase {
                $this->getResult()->addValue(null, $this->getModuleName(), $res);
        }
 
+       public function isWriteMode() {
+               return true;
+       } 
+
        public function getAllowedParams() {
                return array (
                        'title' => null,